/* Orbas:
 *     A open source CORBA Specification implementation from Huihoo.
 *
 * Copyright 2002-2003 Huihoo.org, Inc. All Right Reserved.
 *
 * This software is licensed under LGPL license.
 * See terms of license at gnu.org.
 *
 * For more information, visit:
 *
 * http://www.huihoo.org/orbas
 */



package org.huihoo.orbas.orb.protocols.iiop;

/**
 * <p>Description: </p>
 * TCP connections.
 * <p>Copyright (c) 2002,2003</p>
 * <p>Company: <a href="http://www.huihoo.org/">huihoo.org</a></p>
 * @author <a href="http://www.huihoo.org/~mep">mep(mep@huihoo.com)</a>
 * @see <a href="http://www.huihoo.org/orbas">http://www.huihoo.org/orbas</a>
 * @version 1.0
 */

// TODO: Make IiopChannel a class that can be swapped out with a parameter name.  Make it an abstract class.


import com.cognition.util.j2me.Logger;
import com.cognition.util.j2me.Properties;
import com.cognition.util.j2me.SystemLogger;
import java.io.IOException;
import java.io.InterruptedIOException;
import javax.microedition.io.Connector;
import javax.microedition.io.ServerSocketConnection;
import javax.microedition.io.SocketConnection;
import javax.microedition.io.StreamConnection;
import org.huihoo.orbas.orb.protocols.*;

public class IiopChannel extends Channel 
                implements java.lang.Runnable {

    public static final String LOG_TAG = "IiopChannel";
    private static Logger logger = SystemLogger.getLogger(SystemLogger.LOGGER_CONSOLE);

    private IiopTargetAddress address;
    ServerSocketConnection serverSock;
    SocketConnection clientSock;

    public IiopChannel() {

    }

    public int getProtocolTag() {
        return org.omg.IOP.TAG_INTERNET_IOP.value;
    }

    /**
     * Returns the target address of this channel.
     * @return the address being talked to or null if it's not been set.
     */
    public TargetAddress getTargetAddress() {
        return address;
    }

    /**
     * Attempts to set the server port and opens the socket listener.  If the
     * specified port is 0, then we let the operating system pick the port
     * that it wants.
     * @param port the port to listen to.
     * @throws java.io.IOException
     */
    public void setServerPort(int port)
        throws java.io.IOException {

            if (port > 65535)
                throw new IOException("port requested must be betwee 0 and 65535");

            StringBuffer buf = new StringBuffer();
            buf.append("socket://");

            if (port > 0){
                buf.append(":");
                buf.append(Integer.toString(port));
            }



            String suffix = org.omg.CORBA.ORB.getProperty(Properties.PROP_IIOP_SUFFIX);
            if (suffix != null)
                buf.append(suffix);

            String s = buf.toString();
            logger.debug(LOG_TAG, "opening server connection using '" + buf.toString() +
                    "'.");
            
            serverSock = (ServerSocketConnection)Connector.open(s);

            logger.debug(LOG_TAG, "server listening on port " +
                    serverSock.getLocalPort() + " requested was " + port);

    }

    /**
     * Returns the server port that is being listened to, or -1 if no port
     * could be created
     * @return the port that is currently being listened to or -1 if the port
     *         cannot be retrieved.
     */
    public int getServerPort() {
        int result = -1;
        try{
            if (serverSock != null)
                result = serverSock.getLocalPort();
        } catch (IOException ex){
            System.err.println("IiopChannel: could not retrieve port.");
            ex.printStackTrace();
        }
        return result;
    }

    public String getServerAddress() throws IOException {
        if (serverSock != null)
            return serverSock.getLocalAddress();

        throw new IOException("server socket not opened.");
    }
    
    public void setTargetAddress(TargetAddress a) {
        address = (IiopTargetAddress)a;
    }

    /**
     * Call made to set up client side of the communication pair.
     * @return the transport that handles the connection.
     */
    public Transport setup() {
        
        try {
            if (address == null)
                throw new IOException(
                    "address in the IIOP Channel must be set prior to calling setup.");

            if (address.getHost() == null || address.getHost().equals(""))
                throw new IOException(
                        "no address setup in the channel.");


            StringBuffer buf = new StringBuffer();
            buf.append("socket://");
            buf.append(address.getHost());
            buf.append(":");
            buf.append(Integer.toString(address.getPort()));

            String suffix = org.omg.CORBA.ORB.getProperty(Properties.PROP_IIOP_SUFFIX);
            if (suffix != null)
                buf.append(suffix);

            String s = buf.toString();

            logger.debug(LOG_TAG, "opening client side connection to " + s);
            clientSock = (SocketConnection)Connector.open(s);

            return new IiopTransport(this, clientSock, address);
        }
        catch(java.io.IOException ioex) {
            System.out.println(ioex.toString());
            ioex.printStackTrace();
            
        }
        
        return null;
    }

    /**
     * Tears down the client side of a connection.
     */
    public void teardown() {
        try{
            if (serverSock != null)
                serverSock.close();
        } catch (IOException ex){
            logger.warn(LOG_TAG, "unable to close server socket.");
        }

        try{
            if (clientSock != null)
                clientSock.close();
        } catch (IOException ex){
            logger.warn(LOG_TAG, "unable to close client socket.");
        }
    }

    public void run() {

    }
    
    public Transport accept() {
        

        try {
            long cur = System.currentTimeMillis();
            System.out.println("IiopChannel: call acceptAndOpen at " + cur);
            SocketConnection conn = (SocketConnection)serverSock.acceptAndOpen();
            long dur = System.currentTimeMillis() - cur;
            System.out.println("IiopChannel: acceptAndOpen blocked for " + dur + " ms.");

            return new IiopTransport(conn);
            
        } catch (java.io.IOException e) {
            //If the Acceptor has not been shutdown 
            System.out.println("Server Socket IO Exception" + e);
            return null;
        }
    }
}